package com.lry.basic.jvm.classLoader.demo1;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class MyClassLoader  extends ClassLoader {

    public String rootPath; //rootPath =  F:\lry\project\springboot2\target\classes

    public List<String> clazzs;

    public MyClassLoader(String rootPath,String... classPaths)throws Exception {
        this.rootPath = rootPath;
        this.clazzs = new ArrayList<>();
        //classPath =  F:\lry\project\springboot2\target\classes\cl
        for(String classPath:classPaths){
            scanClassPath(new File(classPath));
        }
    }

    private void scanClassPath(File file) throws Exception {
        if(file.isDirectory()){
            for (File listFile : file.listFiles()) {
                scanClassPath(listFile);
            }
        }else{
            String fileName = file.getName();//MyClassLoader.class
            String filePath = file.getPath();//F:\lry\project\springboot2\target\classes\cl\MyClassLoader.class
            String suffix = fileName.substring(fileName.lastIndexOf("."));
            if(suffix.equals(".class")){
                InputStream is = new FileInputStream(file);
                byte[] bytes = new byte[(int) file.length()];

                is.read(bytes);
                //className = cl.MyClassLoader
                String className = fileNameToClassName(filePath);
                //字节码bytes——>class文件,把clss文件放进jvm缓存,使得findLoadedClass能够找到
                defineClass(className,bytes,0,bytes.length);
                clazzs.add(className);
            }

        }
    }

    private String fileNameToClassName(String filePath) {
        String className = filePath.replace(rootPath,"").replaceAll("\\\\",".");

        className = className.substring(1,className.lastIndexOf("."));

        return className;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        //我们要热部署的代码已经被defineClass缓存起来,findLoadedClass都能找到,就不会走下面的双亲委派了
        Class<?> loadClass = findLoadedClass(name);
        //第一情况 这个类 不需要由我们加载
        //第二种情况 这个类需要由我们加载 但是 确实加载不到
        if(loadClass==null){
            if (!clazzs.contains(name)){
                loadClass = getSystemClassLoader().loadClass(name);
            }else{
                throw  new ClassNotFoundException("没有加载到类"+name);
            }
        }
        return loadClass;
    }

    public static void main(String[] args) throws Exception {
        String rootPath = MyClassLoader.class.getResource("/").getPath().replaceAll("%20"," ");
        rootPath = new File(rootPath).getPath();
        // rootPath =  F:\lry\project\springboot2\target\classes
        while(true){
            //每走一遍MyClassLoader的构造器就会重新加载一次磁盘文件
            MyClassLoader cl = new MyClassLoader(rootPath,rootPath+"/com/lry/basic/jvm/classLoader/demo1");
            Class<?> aClass = cl.loadClass("com.lry.basic.jvm.classLoader.demo1.Test");
            aClass.getMethod("test").invoke(aClass.newInstance());
            Thread.sleep(2000);
        }
    }
}

